package com.example.demo12_rememberme.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("wangnian").password("123").roles("admin");
    }

    /**
     * rememberMe 的思路：当登录成功后，会生成一个 remember-me,关闭浏览器的重新访问服务器，就会带上这个 remember-me，服务端解析这个 remember-me，验证是否合法
     * <p>
     * 登录成功后 会执行 TokenBasedRememberMeServices#onLoginSuccess，至于是如何走到 onLoginSuccess 方法的，参考如下
     * AbstractAuthenticationProcessingFilter#doFilter ->
     * AbstractAuthenticationProcessingFilter#successfulAuthentication ->
     * AbstractRememberMeServices#loginSuccess ->
     * TokenBasedRememberMeServices#onLoginSuccess。
     * <p>
     * TokenBasedRememberMeServices#onLoginSuccess
     * 生成一个 rememberMeToke: d2FuZ25pYW46MTczMDc3MjQ3OTY4MTo5OGYyMDlkOTYyNWI0NjI0ODJmMzRhNDMxZTgwNDY0MQ
     * 一个 BASE64 编码的字符串，解析之后是：wangnian:1730772479681:98f209d9625b462482f34a431e804641
     * 第一段 是用户名，这个无需质疑。
     * 第二段 看起来是一个时间戳，默认这是一个两周后的数据。
     * 第三段 是使用 MD5 散列函数算出来的值，他的明文格式是
     * username + ":" + tokenExpiryTime + ":" + password + ":" + key，最后的 key 是一个散列盐值，默认 UUID 字符串。
     * <p>
     * 由于我们自己没有设置 key，key 默认值是一个 UUID 字符串，这样会带来一个问题，就是如果服务端重启，这个 key 会变，
     * 这样就导致之前派发出去的所有 remember-me 自动登录令牌失效，所以，我们可以指定这个 key。
     * <p>
     * 解析 remember-me 有专门的 RememberMeAuthenticationFilter 过滤器来处理
     * 过滤器中会调用 rememberMeServices#autoLogin 方法来提取出 cookie 中的 remember-me 信息并解码
     * 然后调用 processAutoLoginCookie 方法，根据用户名、过期时间、密码（根据用户名查询出来的）、key
     * 通过 MD5 散列函数重新计算出散列值与 浏览器传过来的 remember-me 做比对，就能确认这个令牌是否有效，进而确认登录是否有效。
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().formLogin()
                .and().rememberMe()
                .key("key")
                .and().csrf().disable();

    }
}
